[BITS 32] 
global start
;            Kernel start
extern ___cpu
start:

cli
	mov esp,0x90000
	
	
	jmp stublet


;This is the multiboot header required by grub loader. it specifies the code,data size

ALIGN 4
mboot:

    MULTIBOOT_PAGE_ALIGN	equ 1<<0
    MULTIBOOT_MEMORY_INFO	equ 1<<1
    MULTIBOOT_AOUT_KLUDGE	equ 1<<16
    MULTIBOOT_HEADER_MAGIC	equ 0x1BADB002
    MULTIBOOT_HEADER_FLAGS	equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE
    MULTIBOOT_CHECKSUM	equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
    EXTERN code, bss, end


    dd MULTIBOOT_HEADER_MAGIC
    dd MULTIBOOT_HEADER_FLAGS
    dd MULTIBOOT_CHECKSUM
    
  
    dd mboot
    dd code
    dd bss
    dd end
    dd start

extern _task_buf
extern _irq_remap
extern _init
extern _init_pm
extern _putch
extern _delay
extern _tisr
stublet:

    nop
    nop
    nop
	
;Reload the gdt and idt(int desc table)
call _setgdt

call _setidt

	mov eax,0
	mov ebx,0
	mov ecx,0
	mov edx,0
	mov esi,0
	mov edi,0
	mov ax,SYS_DATA_SEL
	mov ds,ax
	mov es,ax
	mov fs,ax
	mov gs,ax


call _init

jmp $        ;equivalent to while(1);

db 'X'
irmm times 512 db 0


global _mmx_memcpy;(dst,src,count)
_mmx_memcpy:
push ebp
mov ebp,esp
	push ebx
	push ecx
	push edx
	emms
	mov ebx,dword[ebp+8]
	mov edx,dword[ebp+12]
	mov ecx,dword[ebp+16]
	movemmxloop:
		movq mm0,[edx]
		movq mm1,[edx+8]
		movq mm2,[edx+16]
		movq mm3,[edx+24]
		movq mm4,[edx+32]
		movq mm5,[edx+40]
		movq mm6,[edx+48]
		movq mm7,[edx+56]
		movq [ebx],mm0
		movq [ebx+8],mm1
		movq [ebx+16],mm2
		movq [ebx+24],mm3
		movq [ebx+32],mm4
		movq [ebx+40],mm5
		movq [ebx+48],mm6
		movq [ebx+56],mm7
		add ebx,64
		add edx,64
	loop movemmxloop
	pop edx
	pop ecx
	pop ebx
	mov eax,0
pop ebp
ret



global _movsd_memcpy;(dst,src,count)
_movsd_memcpy:
push ebp
mov ebp,esp
	push esi
	push edi
	push ecx
	mov edi,dword[ebp+8]
	mov esi,dword[ebp+12]
	mov ecx,dword[ebp+16]
	rep movsd
	pop ecx
	pop edi
	pop esi
	mov eax,0
pop ebp
ret

global _mmx_memset;(dst,val,count)
_mmx_memset:
push ebp
mov ebp,esp
pusha                 
	mov ebx,dword[ebp+8]
	mov edx,dword[ebp+12]
	mov ecx,dword[ebp+16]
	mov dword[mmxval],edx
	mov dword[mmxval+4],edx
	mov eax,mmxval
	movq mm0,[eax]
	memsetloop:
		movq [ebx],mm0
		movq [ebx+8],mm0
		movq [ebx+16],mm0
		movq [ebx+24],mm0
		movq [ebx+32],mm0
		movq [ebx+40],mm0
		movq [ebx+48],mm0
		movq [ebx+56],mm0
		movq [ebx+64],mm0
		movq [ebx+72],mm0
		movq [ebx+80],mm0
		movq [ebx+88],mm0
		movq [ebx+96],mm0
		movq [ebx+104],mm0
		movq [ebx+112],mm0
		movq [ebx+120],mm0
		add ebx,128
	loop memsetloop
popa
pop ebp
ret	
		
		
mmxval	dd 0
		dd 0	




%macro SMALL_MEMCPY_X86 0
    rep movsb
%endmacro
;-----------------------------------------------------------------------------
; void *memcpy_mmx(void *dst, cont void *src, int size);
;-----------------------------------------------------------------------------

%define MMX_MMREG_SIZE 8
%define MMX_MIN_LEN 0x40  ; 64 byte blocks

ALIGN 16
global _memcpy_mmx
_memcpy_mmx:
  push esi
  push edi

  mov edi, [esp+8+4]
  mov esi, [esp+8+8]
  mov ecx, [esp+8+12]

  ; Is the block > MIN_SIZE in order to benefit from SSE block copying ?
  cmp ecx, MMX_MIN_LEN
  jl near .trailing_bytes       ; Not enough bytes, then just copy them the 386 way

  ; We must align the destination address to a SSE_MMREG_SIZE boundary
  ; to allow max throughput
  mov edx, edi
  and edx, MMX_MMREG_SIZE-1     ; see if it's an aligned address
  je .destination_aligned

  mov eax, ecx                  ; copy the number of bytes to copy
  sub edx, MMX_MMREG_SIZE       ; compute -number of unaligned bytes
  neg edx                       ; edx now holds the number of bytes to copy to the unaligned dest
  sub eax, edx                  ; computes the remaining number of aligned bytes to copy during the sse2 memcpy
  mov ecx, edx                  ; we will only copy the unaligned bytes for now
  SMALL_MEMCPY_X86
  mov ecx, eax                  ; put to ecx the number of bytes we have still to copy

.destination_aligned
  mov eax, ecx
  shr eax, 6                    ; eax will be the loop counter == number of 64bytes blocks
  and ecx, (64-1)               ; ecx will just keep trace of trailing bytes to copy

ALIGN 8
.block_loop
  movq mm0, [esi+ 0]
  movq mm1, [esi+ 8]
  movq [edi+ 0], mm0
  movq [edi+ 8], mm1
  movq mm2, [esi+16]
  movq mm3, [esi+24]
  movq [edi+16], mm2
  movq [edi+24], mm3
  movq mm4, [esi+32]
  movq mm5, [esi+40]
  movq [edi+32], mm4
  movq [edi+40], mm5
  movq mm6, [esi+48]
  movq mm7, [esi+56]
  movq [edi+48], mm6
  movq [edi+56], mm7
  add esi, 64
  add edi, 64
  dec eax
  jne .block_loop
  emms

  ; Copy the last bytes left after the mmx block copying
  ; ecx must hold the number of remaining bytes to copy
  ; esi must hold the source address
  ; edi must hold the destination address
.trailing_bytes
  cmp ecx, 3
  jg .quite_a_few_trailing_bytes
  SMALL_MEMCPY_X86
  mov eax, [esp+8+12]
  pop edi
  pop esi
  ret
.quite_a_few_trailing_bytes
  BIG_MEMCPY_X86
  mov eax, [esp+8+12]
  pop edi
  pop esi
  ret

;-----------------------------------------------------------------------------
; BIG_MEMCPY_X86(void *dst, cont void *src, int size)
; edi - dst address holder
; esi - src address holder
; ecx - size in bytes
;
;
; NB: well adapted for size >= 4
;-----------------------------------------------------------------------------

%macro BIG_MEMCPY_X86 0
  mov eax, ecx                  ; store for later use
  shr ecx, 2
  rep movsd
  test al, 2                    ; can we move a word ?
  je .dont_move_word
  movsw
.dont_move_word:
  test al, 1
  je .dont_move_byte
  movsb
.dont_move_byte:
%endmacro

;-----------------------------------------------------------------------------
; void *memcpy_sse(void *dst, cont void *src, int size);
;-----------------------------------------------------------------------------

%define SSE_MMREG_SIZE 16
%define SSE_MIN_LEN 0x40        ; 64-byte blocks

ALIGN 16
global _memcpy_sse
_memcpy_sse:
  push esi
  push edi

  mov edi, [esp+8+4]
  mov esi, [esp+8+8]
  mov ecx, [esp+8+12]

  ; Prefetch some data, this is even good for the 386 code: movs(b|w|d)
  prefetchnta [esi]
  prefetchnta [esi+64]
  prefetchnta [esi+128]
  prefetchnta [esi+192]
  prefetchnta [esi+256]

  ; Is the block > MIN_SIZE in order to benefit from SSE block copying ?
  cmp ecx, SSE_MIN_LEN
  jl near .trailing_bytes       ; Not enough bytes, then just copy them the 386 way

  ; We must align the destination address to a SSE_MMREG_SIZE boundary
  ; to allow max throughput
  mov edx, edi
  and edx, SSE_MMREG_SIZE-1     ; see if it's an aligned address
  je .destination_aligned

  mov eax, ecx                  ; copy the number of bytes to copy
  sub edx, SSE_MMREG_SIZE       ; compute -number of unaligned bytes
  neg edx                       ; edx now holds the number of bytes to copy to the unaligned dest
  sub eax, edx                  ; computes the remaining number of aligned bytes to copy during the sse2 memcpy
  mov ecx, edx                  ; we will only copy the unaligned bytes for now
  SMALL_MEMCPY_X86
  mov ecx, eax                  ; put to ecx the number of bytes we have still to copy

.destination_aligned
  mov eax, ecx
  shr eax, 6                    ; eax will be the loop counter == number of 64bytes blocks
  and ecx, (64-1)               ; ecx will just keep trace of trailing bytes to copy
  test esi, (16-1)
  je .aligned_loop

ALIGN 8
.unaligned_loop                 ; SSE block copying (src address is not 16 byte aligned)
  prefetchnta [esi+320]
  movups xmm0, [esi+ 0]
  movups xmm1, [esi+16]
  movntps [edi+ 0], xmm0
  movntps [edi+ 16], xmm1
  movups xmm2, [esi+32]
  movups xmm3, [esi+48]
  movntps [edi+ 32], xmm2
  movntps [edi+ 48], xmm3
  add esi, 64
  add edi, 64
  dec eax
  jne .unaligned_loop
  sfence                        ; back to temporal data
  jmp .trailing_bytes

ALIGN 8
.aligned_loop                   ; SSE block copying (src address is 16 byte aligned)
  prefetchnta [esi+320]
  movaps xmm0, [esi+ 0]
  movaps xmm1, [esi+16]
  movntps [edi+ 0], xmm0
  movntps [edi+ 16], xmm1
  movaps xmm2, [esi+32]
  movaps xmm3, [esi+48]
  movntps [edi+ 32], xmm2
  movntps [edi+ 48], xmm3
  add esi, 64
  add edi, 64
  dec eax
  jne .aligned_loop
  sfence                        ; back to temporal data

  ; Copy the last bytes left after the sse block copying
  ; ecx must hold the number of remaining bytes to copy
  ; esi must hold the source address
  ; edi must hold the destination address
.trailing_bytes
  cmp ecx, 3
  jg .quite_a_few_trailing_bytes
  SMALL_MEMCPY_X86
  mov eax, [esp+8+12]
  pop edi
  pop esi
  ret
.quite_a_few_trailing_bytes
  BIG_MEMCPY_X86
  mov eax, [esp+8+12]
  pop edi
  pop esi
  ret



global _interrupt_flag
_interrupt_flag:
pushf
pop eax
and eax,512
shr eax,9
ret

;proc_fooler is a cpu_state structure with space for all cpu registers.
;save_state_immediate() and load_state_immediate() functions below
; put and load the actual value of registers
 
;Task handling functions:

;This function is only for use in this file. --Oh yes remove global...

extern _proc_fooler  ;Intermediate low level current task state (struct CPU_state)
_save_state_immediate:
mov dword[_proc_fooler+00],eax
mov dword[_proc_fooler+04],ebx
mov dword[_proc_fooler+08],ecx
mov dword[_proc_fooler+12],edx
mov dword[_proc_fooler+16],esi
mov dword[_proc_fooler+20],edi
mov word[_proc_fooler+24],fs
mov word[_proc_fooler+28],gs
mov word[_proc_fooler+32],es
mov word[_proc_fooler+36],ds
mov dword[_proc_fooler+40],esp
mov dword[_proc_fooler+44],ebp
pushf                                 ;Push and pop flags in eax
pop eax
mov dword[_proc_fooler+48],eax
ret

_load_state_immediate:
mov eax,dword[_proc_fooler+00]
mov ebx,dword[_proc_fooler+04]
mov ecx,dword[_proc_fooler+08]
mov edx,dword[_proc_fooler+12]
mov esi,dword[_proc_fooler+16]
mov edi,dword[_proc_fooler+20]
mov fs,word[_proc_fooler+24]
mov gs,word[_proc_fooler+28]
mov es,word[_proc_fooler+32]
mov esp,dword[_proc_fooler+40]
mov ebp,dword[_proc_fooler+44]
mov ds,word[_proc_fooler+36]
push dword[_proc_fooler+48]
popf 
sti
ret


;This function creates a proper stack for a given task entry address and task space,
;so that on iret the task starts executing
extern _process_return
global __set_stack
__set_stack:
push ebp
mov ebp,esp
	pusha
	mov eax,dword[ebp+8]  ;stack
	mov ebx,dword[ebp+12] ;entry address
	mov ecx,dword[ebp+16] ;initflags
		mov dword[tempstack],esp    ;Store current stack
  		mov esp,eax					;Set esp to stack
  		push ecx                    ;Push initflags
  		push SYS_CODE_SEL           ;Push Code selector ring0
  		push ebx					;Push entry address
  		mov dword[taskstack],esp      ;Return resultant stack value
  		mov esp,dword[tempstack]  ;Restore stack
	popa
	mov eax,dword[taskstack]
pop ebp
ret

;Static variables used by setstack
tempstack dd 0
taskstack dd 0 





;System call function used by applications
;Using pusha assuming there is no change in the segment registers
extern __sysfn
global _sysfn
_sysfn:
	pusha
		push edx
		push ecx
		push ebx
		push eax
		call __sysfn  ;C function _sysfn()
		add esp,16
	popa
iret


TS equ 11
ELEN equ 4


extern _print_num 
;Concept behind multitasking:
;As soon as the timer int is executed we save the cpu registers in a temporary
;	structure and while returning from the interrupt we restore cpu registers
;	from the temporary structure. The scheduler which is called by the timer interrupt
;	changes the temporary structure to the task which the kernel should switch to next.
;	Hence while returning from the interrupt when the cpu regs are restored the int returns to
;	a new task thus fooling the earlier task.

;-------------------------------Timer irq0 interrupt ring0-----------------
global _irq0
irq0:
pusha
call _save_state_immediate
call _uirq0
call _load_state_immediate
popa
iret


global _SYSTEM_READ_TIMER
_SYSTEM_READ_TIMER:
push edx
rdtsc                     ;Pentium instruction to read internal timer (reads in eax)
pop edx
ret



;				CR0,CR1,CR2,CR3 are system control registers CR3 stores
;				page directory address,Paging is enabled in CR0
[global _read_cr0]
_read_cr0:
	mov eax, cr0
	retn

[global _write_cr0]
_write_cr0:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr0,  eax
	pop ebp
	retn

[global _read_cr3]
_read_cr3:
	mov eax, cr3
	retn

[global _write_cr3]
_write_cr3:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr3, eax
	pop ebp
	retn

[global _reload_pg]
_reload_pg:
	mov eax,cr3
	mov cr3,eax
	retn

;Load bios interface(Real mode manager) at 0x600 from the 'irmm' pointer above
global _load_lmembm
_load_lmembm:
pusha
mov ax,SYS_DATA_SEL
mov ds,ax
mov ebx,irmm
mov edx,0x600
mov ecx,1024
xfer:
mov al,byte[ds:ebx]
mov byte[ds:edx],al
inc ebx
inc edx
loop xfer
popa
mov eax,0
ret




;					Store bioscall registers at <1MB location for rmm to access
;					and jump to rmm(real mode manager)
;					Rmm will switch mode and execute interrupt
extern _prepare_rm
extern _restore_pm
extern _print_num
global _bioscall
_bioscall: 
push ebp
mov ebp,esp
call _prepare_rm
pusha
mov eax,dword[ds:ebp+8]
mov dword[ds:0x500],eax
mov ebx,dword[ds:ebp+12]
mov dword[ds:0x504],ebx
mov ecx,dword[ds:ebp+16]
mov dword[ds:0x508],ecx
mov edx,dword[ds:ebp+20]
mov dword[ds:0x50c],edx
mov esi,dword[ds:ebp+24]
mov dword[ds:0x510],esi
mov edi,dword[ds:ebp+28]
mov dword[ds:0x514],edi
mov ax,word[ds:ebp+32]
mov word[ds:0x518],ax 

call SYS_CODE_SEL:0x600

mov ax,word[ds:0x518]
mov word[ds:_f],ax

mov eax,[ds:0x500]
mov [_eax],eax
mov ebx,[ds:0x504]
mov [_ebx],ebx
mov ecx,[ds:0x508]
mov [_ecx],ecx
mov edx,[ds:0x50c]
mov [_edx],edx
mov esi,[ds:0x510]
mov [_esi],esi
mov edi,[ds:0x514]
mov [_edi],edi
popa
call _restore_pm
pop ebp
ret


global _callbios
_callbios:
call SYS_CODE_SEL:0x600			;Unprotected call (add critical before calling)
ret

global _save_state
_save_state:
mov dword[tcx],ecx
mov ecx,dword[esp+4]
mov dword[ecx],esp
mov dword[ecx+4],ebp
mov dword[ecx+8],eax
mov dword[ecx+12],ebx
mov eax,dword[tcx]
mov dword[ecx+16],eax
mov dword[ecx+20],edx
mov dword[ecx+24],esi
mov dword[ecx+28],edi
ret

tcx dd 0

global _load_state
_load_state:
mov ecx,dword[esp+4]
mov esp,dword[ecx]
mov ebp,dword[ecx+4]
mov eax,dword[ecx+8]
mov ebx,dword[ecx+12]
mov edx,dword[ecx+20]
mov esi,dword[ecx+24]
mov edi,dword[ecx+28]
mov ecx,dword[ecx+16]
ret

global _setjmp
_setjmp:
mov ecx,dword[esp+4]
mov dword[ecx],ebx
mov dword[ecx+4],esi
mov dword[ecx+8],edi
mov dword[ecx+12],ebp
pop edx
mov dword[ecx+16],esp
mov dword[ecx+20],edx
xor eax,eax
jmp edx

global _longjmp
_longjmp:
mov eax,dword[esp+8]
mov ecx,dword[esp+4]
mov ebx,dword[ecx]
mov esi,dword[ecx+4]
mov edi,dword[ecx+8]
mov ebp,dword[ecx+12]
mov esp,dword[ecx+16]
or eax,eax
jnz dr
inc eax
dr:
jmp dword[ecx+20]

global _asmdel
_asmdel:
push ebp
mov ebp,esp
push ecx
mov ecx,dword[ds:ebp+8]
loop $ 
pop ecx
pop ebp
ret

global _setgdt
_setgdt:
enter 0,0
pusha
	lgdt [gdt_desc]
	jmp SYS_CODE_SEL:flush_ipq
	flush_ipq:
	mov ax,SYS_DATA_SEL
	mov ds,ax 
	mov es,ax
	mov fs,ax
	mov gs,ax
	mov ss,ax 
popa
leave
ret

global _reload_tables
_reload_tables:
enter 0,0
pusha
	lgdt [gdt_desc]
	lidt [idt_desc]
	jmp SYS_CODE_SEL:flush
	flush:
popa
mov eax,0
leave
ret


extern _default_interrupt
_def_int_asm:
	pusha			; save user-mode GP regs
		call _default_interrupt
	popa
iret


global _setidt
_setidt:
enter 0,0
pusha
	;Set all ints to default handler:
	mov ecx,_def_int_asm
	mov edx,0
	setloop:
	call setvect
	inc edx
	cmp edx,255
	jnae setloop
	call set_intel_efa
	lidt [idt_desc]
popa
mov eax,0
leave
ret

%macro setvector 1-2
mov ecx,%2
mov edx,%1
call setvect
%endmacro


extern _keyboard
global _set_all_irqs
_set_all_irqs:
setvector 0x20,irq0
setvector 0x21,irq1
setvector 0x22,irq2
setvector 0x23,irq3
setvector 0x24,irq4
setvector 0x25,irq5
setvector 0x26,irq6
setvector 0x27,irq7
setvector 0x28,irq8
setvector 0x29,irq9
setvector 0x2a,irq10
setvector 0x2b,irq11
setvector 0x2c,irq12
setvector 0x2d,irq13
setvector 0x2e,irq14
setvector 0x2f,irq15
setvector 0x30,_sysfn
ret


extern _uirq0
extern _uirq1
extern _uirq2
extern _uirq3
extern _uirq4
extern _uirq5
extern _uirq6
extern _uirq7
extern _uirq8
extern _uirq9
extern _uirq10
extern _uirq11
extern _uirq12
extern _uirq13
extern _uirq14
extern _uirq15


%macro irq_function 1
irq%1:
	pusha	
	call _uirq%1
	popa
iret
%endmacro

;irq0 defined earlier as timer used for scheduling
irq_function 1
irq_function 2
irq_function 3
irq_function 4
irq_function 5
irq_function 6
irq_function 7
irq_function 8
irq_function 9
irq_function 10
irq_function 11
irq_function 12
irq_function 13
irq_function 14
irq_function 15


;								setvect routine sets interrupt vectors in the idt below

setvect:
pusha
mov eax,edx
mov ebx,8
mul ebx
mov edx,eax
xor eax,eax
mov ax,cx
shr ecx,16
mov bx,cx
mov ecx,edx
mov [idt+ecx],ax
mov [idt+ecx+6],bx
popa
ret


global _getcpu
_getcpu:
pusha
mov dword[ds:_cpu_eax],eax
mov dword[ds:_cpu_ebx],ebx
mov dword[ds:_cpu_ecx],ecx
mov dword[ds:_cpu_edx],edx
mov dword[ds:_cpu_esp],esp
mov dword[ds:_cpu_ebp],ebp
mov dword[ds:_cpu_esi],esi
mov dword[ds:_cpu_edi],edi
mov word[ds:_cpu_cs],cs
mov word[ds:_cpu_ds],ds
mov word[ds:_cpu_ss],ss
mov word[ds:_cpu_fs],fs
mov word[ds:_cpu_gs],gs
mov word[ds:_cpu_es],es
mov eax,cr0
mov dword[ds:_cpu_cr0],eax
mov eax,cr3
mov dword[ds:_cpu_cr3],eax
pop eax
push eax
mov dword[ds:_cpu_espp],eax
pushf
pop eax
mov dword[ds:_cpu_eflags],eax
popa
ret


set_intel_efa:
mov ecx,ex0h
mov edx,0
call setvect
mov ecx,ex1h
mov edx,1
call setvect
mov ecx,ex2h
mov edx,2
call setvect
mov ecx,ex3h
mov edx,3
call setvect
mov ecx,ex4h
mov edx,4
call setvect
mov ecx,ex5h
mov edx,5
call setvect
mov ecx,ex6h
mov edx,6
call setvect
mov ecx,ex7h
mov edx,7
call setvect
mov ecx,ex8h
mov edx,8
call setvect
mov ecx,ex9h
mov edx,9
call setvect
mov ecx,ex10h
mov edx,10
call setvect
mov ecx,ex11h
mov edx,11
call setvect
mov ecx,ex12h
mov edx,12
call setvect
mov ecx,ex13h
mov edx,13
call setvect
mov ecx,ex14h
mov edx,14
call setvect
mov ecx,ex15h
mov edx,15
call setvect
mov ecx,ex16h
mov edx,16
call setvect
mov ecx,ex17h
mov edx,17
call setvect
mov ecx,ex18h
mov edx,18
call setvect
ret

extern _ex0
extern _ex1
extern _ex2
extern _ex3
extern _ex4
extern _ex5
extern _ex6
extern _ex7
extern _ex8
extern _ex9
extern _ex10
extern _ex11
extern _ex12
extern _ex13
extern _ex14
extern _ex15
extern _ex16
extern _ex17
extern _ex18

ex0h:
pusha
	call _ex0
popa
iret
ex1h:
pusha
	call _ex1
popa
iret
ex2h:
pusha
	call _ex2
popa
iret
ex3h:
pusha
	call _ex3
popa
iret
ex4h:
pusha
	call _ex4
popa
iret
ex5h:
pusha
	call _ex5
popa
iret
ex6h:
pusha
	call _ex6
popa
iret
ex7h:
pusha
	call _ex7
popa
iret
ex8h:
pusha
	call _ex8
popa
iret
ex9h:
pusha
	call _ex9
popa
iret
ex10h:
pusha
	call _ex10
popa
iret
ex11h:
pusha
	call _ex11
popa
iret
ex12h:
pusha
	call _ex12
popa
iret
ex13h:
pusha
	call _ex13
popa
iret
ex14h:
pusha
	call _ex14
popa
iret
ex15h:
pusha
	call _ex15
popa
iret
ex16h:
pusha
	call _ex16
popa
iret
ex17h:
pusha
	call _ex17
popa
iret
ex18h:
pusha
	call _ex18
popa
iret


section .data

global _start
_start dd start
global _end
_end dd end

global _cpu_eax
_cpu_eax dd 0
global _cpu_ebx
_cpu_ebx dd 0
global _cpu_ecx
_cpu_ecx dd 0
global _cpu_edx
_cpu_edx dd 0
global _cpu_esp
_cpu_esp dd 0
global _cpu_ebp
_cpu_ebp dd 0
global _cpu_esi
_cpu_esi dd 0
global _cpu_edi
_cpu_edi dd 0
global _cpu_cs
_cpu_cs dd 0
global _cpu_ds
_cpu_ds dd 0
global _cpu_ss
_cpu_ss dd 0
global _cpu_fs
_cpu_fs dd 0
global _cpu_gs
_cpu_gs dd 0
global _cpu_es
_cpu_es dd 0
global _cpu_cr0
_cpu_cr0 dd 0
global _cpu_cr3
_cpu_cr3 dd 0
global _cpu_espp
_cpu_espp dd 0
global _cpu_eflags
_cpu_eflags dd 0

biosregs:
;32 bit return registers:
global _eax
_eax dd 0
global _ebx
_ebx dd 0
global _ecx
_ecx dd 0
global _edx
_edx dd 0
global _esi
_esi dd 0
global _edi
_edi dd 0
global _f
_f dw 0


gdt:

gdt_null:
        dd 0
        dd 0

SYS_CODE_SEL	equ	$-gdt
gdt_code:
        dw 0FFFFh
        dw 0
        db 0
        db 0x9A
        db 0xCF
        db 0

SYS_DATA_SEL	equ	$-gdt
gdt_data:
        dw 0FFFFh
        dw 0
        db 0
        db 0x92
        db 0xCF
        db 0

REAL_CODE_SEL	equ	$-gdt
gdt3:	dw 0xFFFF
	dw 0
	db 0
	db 0x9A
	db 0
	db 0
	
REAL_DATA_SEL	equ	$-gdt
gdt4:	dw 0xFFFF
	dw 0x100
	db 0
	db 0x92
	db 0
	db 0
       
gdt_end:


gdt_desc: 
        dw gdt_end - gdt - 1
        dd gdt

%macro idt_entry 1
		dw 0x00
		dw SYS_CODE_SEL
		db 0x00
		db 0x8e
		dw 0x00
%endmacro

%macro idt_entry_ring3 1
        dw 0x00
		dw SYS_CODE_SEL
		db 0x00
		db 0xee
		dw 0x00
%endmacro

idt:
idt_entry 0
idt_entry 1
idt_entry 2
idt_entry 3
idt_entry 4
idt_entry 5
idt_entry 6
idt_entry 7
idt_entry 8
idt_entry 9
idt_entry 10
idt_entry 11
idt_entry 12
idt_entry 13
idt_entry 14
idt_entry 15
idt_entry 16
idt_entry 17
idt_entry 18
idt_entry 19
idt_entry 20
idt_entry 21
idt_entry 22
idt_entry 23
idt_entry 24
idt_entry 25
idt_entry 26
idt_entry 27
idt_entry 28
idt_entry 29
idt_entry 30
idt_entry 31
idt_entry 32
idt_entry 33
idt_entry 34
idt_entry 35
idt_entry 36
idt_entry 37
idt_entry 38
idt_entry 39
idt_entry 40
idt_entry 41
idt_entry 42
idt_entry 43
idt_entry 44
idt_entry 45
idt_entry 46
idt_entry 47
idt_entry 48			;System call
idt_entry 49
idt_entry 50
idt_entry 51
idt_entry 52
idt_entry 53
idt_entry 54
idt_entry 55
idt_entry 56
idt_entry 57
idt_entry 58
idt_entry 59
idt_entry 60
idt_entry 61
idt_entry 62
idt_entry 63
idt_entry 64
idt_entry 65
idt_entry 66
idt_entry 67
idt_entry 68
idt_entry 69
idt_entry 70
idt_entry 71
idt_entry 72
idt_entry 73
idt_entry 74
idt_entry 75
idt_entry 76
idt_entry 77
idt_entry 78
idt_entry 79
idt_entry 80
idt_entry 81
idt_entry 82
idt_entry 83
idt_entry 84
idt_entry 85
idt_entry 86
idt_entry 87
idt_entry 88
idt_entry 89
idt_entry 90
idt_entry 91
idt_entry 92
idt_entry 93
idt_entry 94
idt_entry 95
idt_entry 96
idt_entry 97
idt_entry 98
idt_entry 99
idt_entry 100
idt_entry 101
idt_entry 102
idt_entry 103
idt_entry 104
idt_entry 105
idt_entry 106
idt_entry 107
idt_entry 108
idt_entry 109
idt_entry 110
idt_entry 111
idt_entry 112
idt_entry 113
idt_entry 114
idt_entry 115
idt_entry 116
idt_entry 117
idt_entry 118
idt_entry 119
idt_entry 120
idt_entry 121
idt_entry 122
idt_entry 123
idt_entry 124
idt_entry 125
idt_entry 126
idt_entry 127
idt_entry 128
idt_entry 129
idt_entry 130
idt_entry 131
idt_entry 132
idt_entry 133
idt_entry 134
idt_entry 135
idt_entry 136
idt_entry 137
idt_entry 138
idt_entry 139
idt_entry 140
idt_entry 141
idt_entry 142
idt_entry 143
idt_entry 144
idt_entry 145
idt_entry 146
idt_entry 147
idt_entry 148
idt_entry 149
idt_entry 150
idt_entry 151
idt_entry 152
idt_entry 153
idt_entry 154
idt_entry 155
idt_entry 156
idt_entry 157
idt_entry 158
idt_entry 159
idt_entry 160
idt_entry 161
idt_entry 162
idt_entry 163
idt_entry 164
idt_entry 165
idt_entry 166
idt_entry 167
idt_entry 168
idt_entry 169
idt_entry 170
idt_entry 171
idt_entry 172
idt_entry 173
idt_entry 174
idt_entry 175
idt_entry 176
idt_entry 177
idt_entry 178
idt_entry 179
idt_entry 180
idt_entry 181
idt_entry 182
idt_entry 183
idt_entry 184
idt_entry 185
idt_entry 186
idt_entry 187
idt_entry 188
idt_entry 189
idt_entry 190
idt_entry 191
idt_entry 192
idt_entry 193
idt_entry 194
idt_entry 195
idt_entry 196
idt_entry 197
idt_entry 198
idt_entry 199
idt_entry 200
idt_entry 201
idt_entry 202
idt_entry 203
idt_entry 204
idt_entry 205
idt_entry 206
idt_entry 207
idt_entry 208
idt_entry 209
idt_entry 210
idt_entry 211
idt_entry 212
idt_entry 213
idt_entry 214
idt_entry 215
idt_entry 216
idt_entry 217
idt_entry 218
idt_entry 219
idt_entry 220
idt_entry 221
idt_entry 222
idt_entry 223
idt_entry 224
idt_entry 225
idt_entry 226
idt_entry 227
idt_entry 228
idt_entry 229
idt_entry 230
idt_entry 231
idt_entry 232
idt_entry 233
idt_entry 234
idt_entry 235
idt_entry 236
idt_entry 237
idt_entry 238
idt_entry 239
idt_entry 240
idt_entry 241
idt_entry 242
idt_entry 243
idt_entry 244
idt_entry 245
idt_entry 246
idt_entry 247
idt_entry 248
idt_entry 249
idt_entry 250
idt_entry 251
idt_entry 252
idt_entry 253
idt_entry 254
idt_entry 255


idt_end:

idt_desc:
        dw idt_end - idt - 1
        dd idt
